本文同步更新於blog
情境:讓我們利用備忘錄模式,實作一個仿真Git
<?php
namespace App\MementoPattern\Git;
/**
* This is our Memento in memento pattern
*/
class Commit
{
/**
* This is our state.
*
* @var string
*/
private $code;
public function __construct(string $code)
{
$this->code = $code;
}
public function getCode(): string
{
return $this->code;
}
}
Commit屬於備忘錄類別 (Memento),
負責儲存 原始類別 (Originator) 的狀態。
在這個範例中,code就是我們的狀態。
<?php
namespace App\MementoPattern\Git;
use App\MementoPattern\Git\Commit;
/**
* This is our CareTaker in memento pattern
*/
class Folder
{
/**
* @var Commit[]
*/
private $commits = [];
/**
* @param Commit $commit
*/
public function saveCommit(Commit $commit)
{
$this->commits[] = $commit;
}
/**
* @param int $previous
* @return Commit
*/
public function getPreviousCommit(int $previous): Commit
{
$commitAmount = count($this->commits);
$index = $commitAmount - $previous;
$result = $this->commits[$index];
return $result;
}
}
Folder屬於管理類別 (Caretaker),
負責管理Commit的存儲。
<?php
namespace App\MementoPattern\Git;
use App\MementoPattern\Git\Commit;
use App\MementoPattern\Git\Folder;
/**
* This is our Originator in memento pattern
*/
class Git
{
/**
* @var Folder
*/
protected $folder;
/**
* This is our state.
*
* @var string
*/
private $code;
/**
* @param Folder $folder
*/
public function __construct(Folder $folder)
{
$this->folder = $folder;
}
/**
* Getter
*
* @return string
*/
public function getUntrackedCode(): string
{
return $this->code;
}
/**
* Setter
*
* @var string
*/
public function writeCode(string $code)
{
$this->code = $code;
}
public function commit()
{
$commit = $this->createCommit();
$this->code = '';
$this->folder->saveCommit($commit);
}
private function createCommit(): Commit
{
return new Commit($this->code);
}
/**
* @param int $previous
* @return string
*/
public function reset(int $previous): string
{
return $this->code = $this->folder->getPreviousCommit($previous)->getCode();
}
}
Git屬於我們的原始類別 (Originator),具有code狀態。
getUntrackedCode()及writeCode()是我們code狀態的Getter/Setter。
透過commit()方法,生成Commit,保存了當下code的狀態,
並傳給Folder作為紀錄存檔。
透過reset()方法,我們可以載入先前存檔好的code狀態。
<?php
namespace App\MementoPattern\Git;
use App\MementoPattern\Git\Folder;
use App\MementoPattern\Git\Git;
class Program
{
public function run()
{
$folder = new Folder();
$git = new Git($folder);
$git->writeCode('aaa');
dump($git->getUntrackedCode()); //aaa
$git->commit();
dump($git->getUntrackedCode()); //''
$git->writeCode('bbb');
$git->commit();
$git->reset(1);
dump($git->getUntrackedCode()); //aaa
}
}
[單一職責原則]
我們將原始類別、備忘錄類別與管理類別視為三種職責。
[開放封閉原則]
透過備忘錄類別與管理類別,
原始類別不需要實作恢復狀態的相關功能。
最後附上類別圖:
(註:若不熟悉 UML 類別圖,可參考UML類別圖說明。)
ʕ •ᴥ•ʔ:這個範例只是利用Git作為媒介,與真實Git行為不完全相同。